/**
 * WTF Engine
 *
 * License... etc.
 **
 * Engine Kernel
 *
 * Provides the following:
 *	- Task base class & task manager;
 *	- Event base class, to notify engine subsystems
 *	  when things happen;
 *  - Game state, to track the game application's event
 *    handlers and tasks;
 *	- The kernel - handles task scheduling, time scaling,
 *	  and the game state stack.
 **
 * Author: Sean Micklethwaite
 **/

#ifndef __kernelH__
#define __kernelH__

#include "mm.h"
#include "functor.h"
#include "prioheap.h"
#include <iostream>
#include <typeinfo>
#include <list>
#include <map>


namespace WtfEngine
{
	/**** Events ****/
	
	/**
	 * The generic event class is always "greater than or equal to" any
	 * other event, and other events must always be "greater than or equal to"
	 * generic events. The implication of this is that generic events seem
	 * to be "equal" to any other event - this is true in the sense that every
	 * event is derived from this class, so an instance of this class represents
	 * the set of all events.
	 **/
	class Event : public GcObject
	{
#	define EVENT(Type, Parent, Comparator) protected: \
		inline int _EventKeyCompare(const Type * pEv) const { \
			return (Comparator); \
		}; \
		inline int EventKeyCompare(const Type * pEv) const { \
			int c = this->Parent::EventKeyCompare(pEv); \
			return (c != 0 ? c : this->Type::_EventKeyCompare(pEv)); \
		}; public: \
		virtual int EventKeyCompare(const Event& ev) const { \
			const Type * pEv = dynamic_cast<const Type *>(&ev); \
			return (pEv == NULL ? this->Parent::EventKeyCompare(ev) : this->Type::EventKeyCompare(pEv)); \
		}; \
		virtual bool Accepts(const Event& ev) const { \
			const Type * pEv = dynamic_cast<const Type *>(&ev); \
			return ((pEv != NULL) && (this->EventKeyCompare(pEv) == 0)); \
		};

	public:
		typedef GcReference<Event>	tRef;

		typedef enum {
			/// There is no active event
			NONE = 0,

			/// Event has not been processed
			PROPAGATING = 1,
			
			/// Event has been processed, but is still passed to other
			/// handlers
			PROCESSED = 2,

			/// Event has been processed, and will not be passed to other
			/// handlers
			STOPPED = 3
		} tEventStatus;

		virtual ~Event() {};
		
		/**
		 * This method exists to provide a linear order on events, which is
		 * crucial to the logarithmic running time of event processing.
		 **/
		inline bool operator < (const Event& ev) const{
			return (this->EventKeyCompare(ev) < 0);
		};

		/**
		 * The Accepts method exists to provide subsetting of events.
		 * This method returns true if this object is a superset
		 * of the supplied operand.
		 **/
		virtual bool Accepts(const Event& ev) const {
			return true;
		};

		/// Default key comparator - equal to everything (set of all events)
		inline int EventKeyCompare(const Event * pEv) const {
			return 0;
		};
		virtual int EventKeyCompare(const Event& ev) const {
			return 0;
		};

	protected:
		/**
		 * Event type info
		 **/
		class EventType {
			int miEventType;
			
		public:
			inline EventType(): miEventType(_Register()) {
			};

			inline operator int () const {
				return miEventType;
			};

		private:
			static inline int _Register() {
				static int iLastKey = 0;
				return iLastKey++;
			};
		};
	};

	/**
	 * This event class orders on the EventType information
	 * generated from instances of the template. Thus events
	 * with the same SuperiorType are considered equal.
	 **/
#	define EVENT_TYPE_FORK(Type, Parent, ArgsDecl, Args) \
	class __##Type : public Parent { \
		protected: inline __##Type(ArgsDecl): Parent(Args) { }; \
		virtual const EventType& __Get##Type() const = 0; \
		EVENT(__##Type, Parent, ((int)__Get##Type() - (int)pEv->__Get##Type())); \
	}; \
	template <class SuperiorType> class Type : public __##Type { \
		static EventType	__EventType; \
		protected: const EventType& __Get##Type() const { return __EventType; }; \
		public: inline Type(ArgsDecl): __##Type(Args) { }; \
		GC_OBJECT(Type<SuperiorType>, GC_ADDEDSIZE_AUTO(Parent, Type<SuperiorType>)); \
	}; \
	template <class SuperiorType> Event::EventType Type<SuperiorType>::__EventType;
	
	// Declare the KeyedEvent class
	EVENT_TYPE_FORK(KeyedEvent, Event, void, );

	class EventRefCmp : public std::less<Event::tRef>
	{
	public:
		/// implements less
		/// NOTE: this has subtle semantics, i.e. considers any overlapping
		/// event set to be equal (returns false). An order can only be defined
		/// using this relation on disjoint sets.
		bool operator ()(const Event::tRef& e1, const Event::tRef& e2) const{
			return ((!e1->Accepts(*e2)) && ((*e1) < (*e2)));
		};
	};

	
	/**
	 * Event handlers wrap functors, and are mapped to keyed events. They are
	 * ordered by priority and bind time, so higher priority and newer handlers
	 * will be called first.
	 **/
	class EventHandler {
	public:
		typedef enum {
			/// Event handlers with this priority will be skipped.
			PRIO_DISABLED = 0,

			/// The kernel will run numerically higher priority event handlers
			/// first.
			PRIO_DECORATIVE = 1,
			PRIO_DEFAULT,
			PRIO_GAME_LOCAL,
			PRIO_GAME_REMOTE,
			PRIO_GAME_HIGH,
			PRIO_WM,
			PRIO_WM_HIGH,
			PRIO_GAME_CRITICAL,
			PRIO_WM_CRITICAL
		} tPriority;

	private:
		Functor::tRef	mrHandler;
		/// Bind time (in system time)
		tGameTime		mBindTime;
		tPriority		mPriority;
		
	public:
		/// Contructor and implicit conversion from functor
		inline EventHandler(const Functor::tRef& rHandler):
		mPriority(PRIO_DEFAULT) {
			setHandler(rHandler);
		};
		/// Contructor and implicit conversion from functor pointer
		inline EventHandler(Functor* pHandler):
		mPriority(PRIO_DEFAULT) {
			setHandler(pHandler);
		};

		inline EventHandler(const Functor::tRef& rHandler, tPriority prio):
		mPriority(prio) {
			setHandler(rHandler);
		};

		/// Copy constructor
		inline EventHandler(const EventHandler& eh):
		mPriority(eh.mPriority) {
			setHandler(eh.getHandler());
		};
		/// Assignment
		inline void operator = (const EventHandler& eh) {
			setHandler(eh.mrHandler);
			setPriority(eh.mPriority);
		};

		// Properties
		inline const Functor::tRef& getHandler() const {
			return mrHandler;
		};
		void setHandler(const Functor::tRef& rHandler);

		inline tGameTime getBindTime() const {
			return mBindTime;
		};

		inline tPriority getPriority() const {
			return mPriority;
		};
		inline void setPriority(tPriority prio) {
			mPriority = prio;
		};

		/// Priority Comparison
		inline bool operator < (const EventHandler& eh) const {
			return ((mPriority < eh.mPriority) ||
				((mPriority == eh.mPriority) && (mBindTime < eh.mBindTime)));
		};

		/// Event handler comparison
		inline bool operator == (const EventHandler& eh) const {
			return (*mrHandler == *eh.mrHandler);
		};
	};

	class IEventChannel: public virtual IGcObject {
	public:
		virtual ~IEventChannel() {};

		virtual void BindEvent(const Event::tRef& ev, const EventHandler& eh) = 0;
		virtual void ClearEvents(const Event::tRef& ev) = 0;
		virtual void RemoveHandler(const EventHandler& eh) = 0;

		GC_INTERFACE(IEventChannel);
	};

	/**
	 * Event channels represent a particular level of event specialisation.
	 * They each have a tree of children (which are the subsets) which are ordered. Each
	 * child is itself a channel, and groups together similar events. As such, the events
	 * are stored in a "tree of trees", with parent channels accepting events from all
	 * its children.
	 **/
	class EventChannel: public virtual IEventChannel, public GcObject {
		GC_AUTOSIZE(EventChannel);
	private:
		static EventRefCmp gEventRefCmp;

		/**
		 * This struct wraps pointers to event handlers so they can be
		 * inserted into a priority queue.
		 **/
		struct EventHandlerPriorityQueueEntry {
			const EventHandler * pHandler;

			inline EventHandlerPriorityQueueEntry(const EventHandler& handler)
			: pHandler(&handler) {};

			inline bool operator < (const EventHandlerPriorityQueueEntry& ent) const {
				return (*pHandler < *(ent.pHandler));
			};

			inline void Invoke() const {
				pHandler->getHandler()->operator ()();
			};
		};

		typedef Rtl::BinaryHeap<EventHandlerPriorityQueueEntry, Rtl::BinaryHeapType::MaxHeap<EventHandlerPriorityQueueEntry>
			> tEventHandlerPriorityQueue;

		typedef std::map<Event::tRef, GcReference<EventChannel>, EventRefCmp> tEventMap;

		Event::tRef					rEvent;
		tEventMap					vEventMap;
		tEventHandlerPriorityQueue	vEventHandlerQueue;
		std::list<EventHandler>		vEventHandlers;

	public:
		explicit EventChannel(const Event::tRef& rEv)
		: rEvent(rEv), vEventMap(gEventRefCmp) {
		};

		void BindEvent(const Event::tRef& ev, const EventHandler& eh);

		Event::tEventStatus ProcessEvent(const Event::tRef& ev, volatile Event::tEventStatus& Status);

		EventChannel::tEventMap::iterator		LookupChannel(const Event::tRef& ev);
		EventChannel::tEventMap::const_iterator LookupChannel(const Event::tRef& ev) const;

		void ClearEvents(const Event::tRef& ev);
		tRef Clone() const;

		unsigned CountHandlers() const;

		inline void InsertHandler(const EventHandler& eh) {
			vEventHandlers.push_back(eh);
			vEventHandlerQueue.Insert(EventHandlerPriorityQueueEntry(*(vEventHandlers.rbegin())));
		};
		void RemoveHandler(const EventHandler& eh);

	protected:
		inline void InsertChannel(const EventChannel::tRef& rChannel) {
			assert(vEventMap.insert(std::pair<Event::tRef, tRef>(rChannel->rEvent, rChannel)).second);
		};
	};

	/**** Game States ****/

	/**
	 * Application state interface, provides timing and event processing functions. This
	 * is implemented by stacked GameStates and the global kernel.
	 **/
	class IAppState: public virtual IEventChannel {
	public:
		virtual ~IAppState() {};

		virtual tGameTime GetTime() const = 0;
		virtual tGameTime GetDelta() const = 0;

		GC_INTERFACE(IAppState);
	};

	class GameState : public virtual IAppState, public EventChannel
	{
	public:
		typedef GcReference<GameState>	tRef;

		typedef enum {
			STATE_TIMED=1,			// Time is updated
			STATE_REALTIME=2,		// Deltas are calculated
			STATE_UPDATETIME=4,		// Changes to time are kept
			STATE_COPYEVENTS=8,		// Inherits events from parent
			STATE_UPDATEEVENTS=0x10,	// Parent recieves events from this
			STATE_LOGEVENTS=0x20		// Events are logged and kept
		} tStateAttributes;
		
	protected:
		tRef		mParent;
		tGameTime	mGameStart;
		tGameTime	mGameTime;
		tGameTime	mTimeDelta;
		tScalar		mTimeScale;
		bool		mbUpdateParent;

	private:
		EventChannel::tRef	mrEventChannel;

	public:
		GameState();
		virtual ~GameState();

		inline tScalar getTimeScale() const {
			return mTimeScale;
		};
		inline void setTimeScale(tScalar ts) {
			mTimeScale = ts;
		};

		/// Gets the elapsed game time.
		inline tGameTime GetTime() const {
			return mGameTime;
		};

		/// Gets the change in time since the last frame.
		inline tGameTime GetDelta() const {
			return mTimeDelta;
		};

		/// Returns a reference to the previous game state.
		inline tRef GetPrevious() {
			return mParent;
		};
		
		/// Copies event map of this state to the new state
		tRef				Fork(GameState* pNewState);
		
	protected:
		Event::tEventStatus ProcessEvent(const Event::tRef& ev, volatile Event::tEventStatus& Status) {
			return this->EventChannel::ProcessEvent(ev, Status);
		};

		/// Called every frame
		virtual void Update(tGameTime dt);

		/// Called when the state becomes active
		virtual void Enable() {};
		/// Called when the state becomes inactive
		virtual void Disable();
		/// Called when the state enters the stack
		virtual void Initialize() {};
		/// Called when the state leaves the stack
		virtual void Destroy();

		friend class Kernel;
	};



	/**** Task Management ****/

	/**
	 * Generic task interface. Allows the kernel to
	 * control the task.
	 **/
	class ITask {
		public:
			typedef enum {
				RUNNING,
				READY,
				WAITING,
				PAUSED,
				ZOMBIE
			} tTaskStatus;
		
		protected:
			virtual void Run() = 0;
			virtual void Pause() = 0;
			virtual void Resume() = 0;
			virtual void Wait() = 0;
			virtual void Wake() = 0;
			
			
			virtual void SetProfiler(bool bStart = true) {};
			virtual void DumpProfilerData() const {};
	};
	

	/**
	 * Base task structure, providing default operations, profiling and naming.
	 **/
	class TaskCore: public virtual ITask
	{
	protected:
		tTaskStatus		Status;
		int				Priority;
		const char *	Name;

		tGameTime		mTotalRunTime;
		unsigned		mNumInvocations;

		void SetProfiler(bool bStart = true);
		void DumpProfilerData() const;

	public:
		TaskCore(int prio = 0, const char * name = "Unknown Task")
			: Status(READY), Priority(prio), Name(name),
				mTotalRunTime(0), mNumInvocations(0) {
			std::cout << name << " created" << std::endl;
		};

		virtual ~TaskCore() {};

		void Pause();
		void Resume();
		void Wait();
		void Wake();

		// Allow the kernel to access protected members
		friend class Kernel;
	};


	/**
	 * Task singleton base class - for classes which have one instance.
	 **/
	template <class Class>
	class Task : public Singleton<Class>, public TaskCore
	{
	public:
		Task(int prio = 0, const char * sName = "Unknown Task")
			: Singleton<Class>(), TaskCore(prio, sName) {};
	};


	/**** The Kernel ****/

	class Kernel : public virtual IAppState, public Singleton<Kernel>
	{
	public:
		typedef enum
		{
			SYSTEM_INITIALIZING = 0,
			SYSTEM_READY = 1,
			SYSTEM_RUNNING = 2,
			SYSTEM_EXITING = 3,
			SYSTEM_FAILING = 4,
			SYSTEM_EXITED = 5
		} tSystemStatus;
		
		typedef unsigned	tNodeId;
		

	private:
		tSystemStatus	SystemStatus;

		EventChannel::tRef               mrEventChannel;
		std::vector<Event::tEventStatus> mvCurrentEventStatus;
		std::vector<Event*>              mvpCurrentEvent;

		GameState::tRef State;

		Rtl::PriorityQueue<TaskCore*>	RunQueue;

		tGameTime						mLocalStartTime;
		tGameTime						mRunTime;
		tGameTime						mTimeDelta;

		tNodeId							mNodeId;
		
		void	InsertTask(TaskCore*	task);

	public:
		Kernel();
		~Kernel();

		inline static Kernel *GetKernel() {
			return GetInstancePtr();
		};

		inline void	SetSystemStatus(tSystemStatus s) {
			SystemStatus = s;
		};


		/**** Events ****/

		template <class T>
		inline T*	GetCurrentEvent(){
			assert(mvpCurrentEvent.size() > 0);
			return dynamic_cast<T*>(mvpCurrentEvent[mvpCurrentEvent.size() - 1]);
		};

		inline Event::tEventStatus GetEventStatus() const {
			return mvCurrentEventStatus[mvCurrentEventStatus.size() - 1];
		};

		/// Sets the status of the current event. The status is only set if the
		/// old status is numerically less than the new.
		/// @pre	Running an event handler (GetEventStatus() != EVENT_NONE)
		Event::tEventStatus SetEventStatus(Event::tEventStatus st);

		/// Binds the specified event to the specified handler. The handler will be
		/// called when the event is dispatched.
		void				BindEvent(const Event::tRef& ev, const EventHandler& eh);

		/// Clears all handlers which accept the specified event. Generally called
		/// after forking a game state, in order to set up new handlers.
		void				ClearEvents(const Event::tRef& ev);
		void				RemoveHandler(const EventHandler& eh);

		/// Dispatches the specified event to its handlers, returning the status
		Event::tEventStatus	ProcessEvent(const Event::tRef& ev);


		/**** Game State ****/

		inline GameState::tRef	GetGameState() {
			return State;
		};
		inline GameState*		GetGameStatePtr() {
			return &*State;
		};
		inline void PushGameState(GameState* pNewState) {
			pNewState->mParent = State;
			if(!State.isNull())
				State->Disable();
			State = pNewState;
			State->Initialize();
			State->Enable();
		};
		inline GameState::tRef ForkGameState(GameState* pNewState) {
			GameState::tRef rNewState(State->Fork(pNewState));
			PushGameState(pNewState);
			return rNewState;
		};
		inline void PopGameState(GameState::tRef* prState){
			*prState = State;
			State->Disable();
			State->Destroy();
			State = State->mParent;
			if(!State.isNull())
				State->Enable();
		};
		inline void PopGameState(){
			State->Disable();
			State->Destroy();
			State = State->mParent;
			if(!State.isNull())
				State->Enable();
		};


		void	RunGameLoop();

		tGameTime	GetTime() const;
		inline tGameTime GetDelta() const {
			return mTimeDelta;
		};


		/**** Event Management ****/

		void	ProcessKernelEvents();
		void	FlushLog();


		/**** Task Management ****/

		void	RunTask(TaskCore* task);
		void	WaitTask(TaskCore* task);
		void	WakeTask(TaskCore* task);
		void	PauseTask(TaskCore* task);
		void	ResumeTask(TaskCore* task);


		/**** Misc ****/

		void DumpProfilerData();

		static void DebugPrint(const char *s)
		{
			//std::cout << s << std::endl;
		};
		
		tNodeId GetNodeId() {
			return mNodeId;
		};

		GC_AUTOSIZE(Kernel);
	};

	inline static Kernel *getKernel() {
		return Kernel::GetKernel();
	};


	/**** Frame events ****/

	class FrameStartEvent: public KeyedEvent<FrameStartEvent> {
		GC_AUTOSIZE(FrameStartEvent);
	};
	class FrameEndEvent: public KeyedEvent<FrameEndEvent> {
		GC_AUTOSIZE(FrameEndEvent);
	};
};

#endif
